<template>
  <el-input :style="{ width: proxy.$size(width, '100%') }" v-model="keyword" v-bind="inputProps" @change="changeBtn">
    <!-- 前置 el-select -->
    <template #prepend v-if="select && select.key && select.options">
      <el-select v-model:value="data[select.key]" :placeholder="select.placeholder" :style="{
        width:
          typeof select.width === 'number' ? `${select.width}px` : select.width,
      }" :disabled="typeof $attrs.disabled === 'function'
        ? $attrs.disabled(data)
        : $attrs.disabled
        " :teleported="false" @click.stop>
        <el-option v-for="option in select.options" :key="getOptionValue(option)" :label="getOptionLabel(option)"
          :value="getOptionValue(option)" @click.stop />
      </el-select>
    </template>

    <!-- 后缀单位 -->
    <template #append v-if="$attrs.unit">
      {{ $attrs.unit }}
    </template>

    <!-- 前缀图标 -->
    <template #prefix v-if="icon">
      <IconBox :icon="icon" />
    </template>

    <!-- 其他插槽 -->
    <template #[key] v-for="(_, key) in $slots" :key="key">
      <slot :name="key" />
    </template>
  </el-input>
</template>

<script setup lang="ts">
import { computed, ref, onMounted, watchEffect } from 'vue'
import { getCurrentInstance } from 'vue'

const { proxy } = getCurrentInstance() as any

// =================== Props 定义 ===================
interface SelectOption {
  label?: string
  value?: any
  [key: string]: any
}

interface InputProps {
  data: Record<string, any> | any // 父级传递的数据对象或字符串/数字
  dataName?: string | null // 如果 data 是对象，则此字段表示要绑定的 key
  width?: string | number // 组件宽度
  select?: {
    key: string
    options: Array<SelectOption | string>
    placeholder?: string
    labelName?: string
    valueName?: string
    width?: string | number
  }
  icon?: string
}

const props = withDefaults(defineProps<InputProps>(), {
  data: () => ({}),
  dataName: null,
})

// =================== Emits 定义 ===================
const emit = defineEmits<{
  (event: 'changeBtn', val: any, form: any): void
  (event: 'update:data', value: any): void
}>()

// =================== Computed 属性 ===================
const keyword = computed({
  get(): any {
    if (props.data || props.data === 0) {
      return props.dataName ? props.data[props.dataName] : props.data
    }
    return ''
  },
  set(val: any): void {
    const formattedVal = val
    if (props.dataName) {
      props.data[props.dataName] = formattedVal
    } else {
      emit('update:data', formattedVal)
    }
  },
})

// input 属性合并
const inputProps = computed(() => ({
  placeholder: '请输入',
  clearable: !!props.dataName,
  autosize: { minRows: 3, maxRows: 10 },
  ...proxy.$attrs,
  disabled:
    typeof proxy.$attrs.disabled === 'function'
      ? proxy.$attrs.disabled(props.data)
      : proxy.$attrs.disabled,
  'show-word-limit': !!proxy.$attrs.maxlength,
}))

// 获取 option 的 label 和 value
const getOptionLabel = (option: SelectOption | string): string => {
  if (typeof option === 'string') return option
  return props.select?.labelName ? option[props.select.labelName] : option.label
}

const getOptionValue = (option: SelectOption | string): any => {
  if (typeof option === 'string') return option
  return props.select?.valueName ? option[props.select.valueName] : option.value
}

// =================== Methods 方法 ===================
const changeBtn = (value: any): void => {
  const type = proxy.$attrs.type
  if (type !== 'textarea') {
    if (props.dataName) {
      props.data[props.dataName] = value.trim()
    } else {
      emit('update:data', value)
    }
  }
  emit('changeBtn', value, props.data)
}

// =================== 生命周期 ===================
onMounted(() => {
  const _select = props.select
  const _options = _select?.options

  if (
    _select &&
    _select.key &&
    !props.data[_select.key] &&
    _options &&
    _options.length > 0
  ) {
    const firstOption = _options[0]
    const value = getOptionValue(firstOption)
    props.data[_select.key] = value
  }
})

// =================== 开发环境警告 ===================
if (process.env.NODE_ENV === 'development') {
  watchEffect(() => {
    if (
      (typeof props.data === 'string' || typeof props.data === 'number') &&
      props.data !== keyword.value
    ) {
      console.warn(
        '[BaseInput] 检测到传入的是基本类型数据并被修改，请使用 v-model 或绑定对象形式以保证响应性'
      )
    }
  })
}
</script>

<style scoped></style>